package com.gitee.luosl.cola;

import com.gitee.luosl.cola.lang.Tuple;
import com.gitee.luosl.cola.lang.Tuple2;
import com.gitee.luosl.cola.lang.Tuple3;
import com.gitee.luosl.cola.match.Match;
import com.gitee.luosl.cola.match.cases.Case;
import com.gitee.luosl.cola.match.guard.Guard;
import com.gitee.luosl.cola.stream.StreamWrapper;
import com.gitee.luosl.cola.util.Try;

import java.io.*;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static com.gitee.luosl.cola.match.pattern.Pa.*;

/**
 * Created by luosl on 2021/03/24/19:24
 */
public class Demo {


    public static String readFile(String path) throws IOException {

        FileReader reader = new FileReader(path);
        return "";
    }

    public static void main(String[] args) throws IOException {

        Tuple2<Integer, String> tuple2 = Tuple.of(1, "str"); // 二元组
        Tuple3<Integer, String, Double> tuple3 = Tuple.of(1, "str", 1D);  // 三元组
        Integer data1 = tuple2._1; // 获取第一个元素
        String data2 = tuple2._2; // 获取第二个元素

        Tuple2<String, String> tuple2New = tuple2.map1(Object::toString); // 映射第一个元素
        int apply = tuple2.apply((i, s) -> i + s.length()); // 映射整个元组
        boolean test = tuple2.test((i, s) -> i > s.length()); //  测试一个元组
        tuple2.accept((i, s) -> System.out.println(s)); // 消费一个元组

        BufferedReader br = new BufferedReader(new FileReader("demo.txt"));
        Integer res;
        try {
            String str = br.readLine();
            res = Integer.parseInt(str);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            br.close();
            res = -1;
        }


        Integer result = Try.of(br::readLine)
                .map(Integer::parseInt)
                .andFinally(br::close)
                .getOrElse(-1);

        System.out.println();
        


        int a = new Random().nextInt(100);
        Integer result11 = null;

        /** demo1 **/
        // use if
        if(a == 1){
            result11 = a + 1;
        }else{
            result11 = 0;
        }

        // use match
        String results = Match.of(a).match(
                Case.of(p(1), "one"),
                Case.of(p((Integer i) -> i < 50), Object::toString),
                Case.of(p(), () -> "other")
        );

        /** demo2 **/
        // use if
        String result21 = "";
        if(a < 9){
            result21 = "less 9";
        }else if (a >= 10 && a <= 50){
            result21 = "between 10 and 50";
        }else{
            result21 = "other";
        }

        // use match
        String result22 = Match.of(a).match(
                Case.of(p((Integer i) -> i < 9), () -> "less 9"),
                Case.of(p((Integer i) ->  i >= 10 && i <= 50), () -> "between 10 and 50"),
                Case.of(p(), () -> "other")
        );

        /** demo3 **/
        // use if
        Integer result31 = null;
        Object obj = "" + a;
        if(obj instanceof String){
            String str = (String) obj;
            if(str.contains("0")){
                result31 = 1;
            }else{
                result31 = Integer.parseInt(str);
            }
        }else{
            result31 = 0;
        }

        // use match
        Integer result32 = Match.of(obj).match(
                Case.of(p(String.class), Guard.of(str -> str.contains("0")), () -> 1),
                Case.of(p(String.class), Integer::parseInt),
                Case.of(p(), () -> 0)
        );

        /** demo4 对 Optionl 支持 **/
        Supplier<Optional<Integer>> supplier = () -> {
            int value = new Random().nextInt(100);
            if(value % 2 == 0){
                return Optional.of(value);
            }else{
                return Optional.empty();
            }
        };
        Optional<Integer> opt = supplier.get();

        // use if
        Integer result41 = null;
        if(opt.isPresent()){
            int value = opt.get();
            if(value > 10){
                result41 = value - 10;
            }else{
                result41 = value;
            }
        }else{
            result41 = -1;
        }

        // use match
        Integer result42 = Match.of(opt).match(
                Case.of(pSome(p((Integer i) -> i > 10)), x -> x - 10),
                Case.of(pSome(), Function.identity()),
                Case.of(pNone(), () -> -1)
        );
        Tuple2<Optional<Integer>, User> input = Tuple.of(Optional.of(10), new User(20, "luosl"));
        String aaaaaa = Match.of(input).match(
                Case.of(pTuple(pSome(p(10)), pPeek(User::getAge, p(20))), (i, user) -> user.getName()),
                Case.of(p(), () -> null)
        );

        // 多值匹配
        Supplier<Integer> randoms = () -> new Random().nextInt(100);
        int a1 = randoms.get();
        int a2 = randoms.get();

        Integer result51 = null;
        if(a1 <= 10 && a2 > 10){
            result51 = a1 + a2;
        }else if(a1 + a2 > 10){
            result51 = a1 - a2;
        }else{
            result51 = -1;
        }

        Integer result52 = Match.of(a1, a2).match(
                Case.of(pTuple(p((Integer i) -> i > 10), p((Integer i) -> i < 10)), Integer::sum),
                Case.of(pTuple(p(), p()), (x, y) -> x - y),
                Case.of(p(), () -> -1)
        );

        List<User> users = new ArrayList<>();
        for(int i =0; i<100; i++){
            int nameIdx = new Random().nextInt(100);
            int age = new Random().nextInt(100);
            users.add(new User(age, "name-" + nameIdx));
        }

        // 简化 collect 操作
        List<User> list = StreamWrapper.wrap(users).toList();
        Map<String, User> map = StreamWrapper.wrap(users)
                .toMap(User::getName, Function.identity());
        LinkedBlockingQueue<User> queue = StreamWrapper.wrap(users)
                .toCollection(LinkedBlockingQueue::new);
        Map<String, List<Integer>> group = StreamWrapper.wrap(users)
                .groupBy(User::getName, User::getAge);

        // 增强了排序、去重
        StreamWrapper.wrap(users).sortByDesc(User::getAge); // 按 age 倒序
        StreamWrapper.wrap(users).sortByAsc(User::getAge); // 按 age 升序
        StreamWrapper.wrap(users).distinctBy(User::getName); // 按 name 去重

        // 结合模式匹配
        // stream + if
        List<Integer> ifList = users.stream().map(user -> {
            Integer age = user.getAge();
            if (age == 10 || age == 20 || age == 30) {
                return age;
            } else {
                return -1;
            }
        }).collect(Collectors.toList());

        // 模式匹配
        List<Integer> matchList = StreamWrapper.wrap(users).map(
                Case.of(pPeek(User::getAge, pIn(10, 20, 30)), User::getAge),
                Case.of(p(), () -> -1)
        ).toList();

        // EntryStreamWrapper
        Map<String, User> userMap = new HashMap<>();
        for(User user: users){
            userMap.put(user.getName(), user);
        }


        Map<String, User> entryMap = StreamWrapper.wrapEntry(userMap)
                .mapKeys(name -> name.split("-")[1])
                .toMap(); // 仅对 key 进行 map 操作

        Map<String, Integer> entryMap2 = StreamWrapper.wrapEntry(userMap)
                .mapValues(User::getAge)
                .toMap(); // 仅对 value 进行 map操作

        // 使用 BiPredicate 代替 Predicate
        StreamWrapper.wrapEntry(userMap).filter((name, user) -> user.age > 0);

    }

    static class User{

        private Integer age;
        private String name;

        public User(Integer age, String name) {
            this.age = age;
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}
